/**
 * Description:     对bmp位图进行灰度增强操作。

 * Function:        1. void initGaryscale(GARYSCALEBIT *image)
                        初始化 GARYSCALEBIT 结构中的灰度数组; 根据图像尺寸为灰度像素数据分配内存
                    2. void linearEnhancement(GARYSCALEBIT *image, int a, int b)           
                        线性灰度增强：使用线性变换调整图像的亮度对比度
                    3. void exponentialEnhancement(GARYSCALEBIT *image, int a, int b)      
                        指数灰度增强：使用指数变换调整图像的亮度对比度
                    4. void freeGaryscale(GARYSCALEBIT *image)                             
                        释放灰度数组的动态分配内存

 * Solution:        如果你在使用本头文件时发现了任何问题，请报告issue.

 * Contributer:     张紫瑶
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "imgG.h"


/** 初始化 GARYSCALEBIT 结构中的灰度数组; 根据图像尺寸为灰度像素数据分配内存
* 参数：
* - image：指向包含图像数据的 GARYSCALEBIT 结构的指针
*/
void initGaryscale(GARYSCALEBIT *image)
{
    // 计算总像素点数
    int totalPixels = image->biWidth * image->biHeight;
    // 根据总像素数为灰度数组分配内存
    image->garyscale = (unsigned char *)malloc(totalPixels * sizeof(unsigned char));
    //测试内存分配是否成功，若失败报错：“Fail to allocate the memory”并退出程序
    if (image->garyscale == NULL) {
        printf("Fail to allocate the memory\n");
        exit(EXIT_FAILURE);
    }
}


/** 线性灰度增强：使用线性变换调整图像的亮度对比度
* 参数：
* - image：指向包含图像数据的 GARYSCALEBIT 结构的指针
* - a：对比度因子（乘以灰度值）
* - b：亮度因子（向灰度值添加偏移量）
* 公式：g'(x, y) = a * g(x, y) + b
*/
void linearEnhancement(GARYSCALEBIT *image, int a, int b)
{
    // 计算总像素点数
    int totalPixels = image->biWidth * abs(image->biHeight);
    // 对每个像素点进行线性灰度增强
    for (int i = 0; i < totalPixels; i++) {
        // 确保新值在有效灰度范围 [0, 255] 内
        int newValue = (a * image->garyscale[i] + b);
        // 如果新值超出范围，则将其限制为最接近的有效值
        image->garyscale[i] = (unsigned char)(newValue > 255 ? 255 : (newValue < 0 ? 0 : newValue));
    }
}


/** 指数灰度增强：使用指数变换调整图像的亮度对比度
* 参数：
* - image：指向包含图像数据的 GARYSCALEBIT 结构的指针
* - a：强度调整的比例参数
* - b：调整增强程度的指数参数
*/
void exponentialEnhancement(GARYSCALEBIT *image, int a, int b)
{
    // 计算总像素点数
    int totalPixels = image->biWidth * abs(image->biHeight);
    // 对每个像素点进行指数灰度增强
    for (int i = 0; i < totalPixels; i++) {
        // 确保新值在有效灰度范围 [0, 255] 内
        int newValue = (int)(a * pow(image->garyscale[i], b));
        // 如果新值超出范围，则将其限制为最接近的有效值
        image->garyscale[i] = (unsigned char)(newValue > 255 ? 255 : (newValue < 0 ? 0 : newValue));
    }
}


/** 释放灰度数组的动态分配内存
* 参数：
* - image：指向包含图像数据的 GARYSCALEBIT 结构的指针
*/
void freeGaryscale(GARYSCALEBIT *image)
{
    // 释放释放灰度数组的内存
    free(image->garyscale);
    // 将指针设置为null
    image->garyscale = NULL;
}

